package com.gw2.gw2world.web.server.mod;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.AbstractHttpMessage;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.log4j.Logger;

/** Auth and allow queries on the GW2 trading post
 * @author Athanor
 */
public class TradingPostManager {
	//private static final String LOGIN_URL="https://account.guildwars2.com/login";
	public static final String LOGIN_URL="https://account.guildwars2.com/login?redirect_uri=http%3A%2F%2Ftradingpost-live.ncplatform.net%2Fauthenticate%3Fsource%3D%252F&game_code=gw2";
	public static final String TP_URL="https://tradingpost-live.ncplatform.net/authenticate?id=";
	private final String USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1";
	private String email="", password="";
	private CookieStore cookieStore;
	private HttpContext httpContext;
	private HttpResponse response;
	private int lastErrorCode=0;
	/** Session ID */
	private String sid="";
	public TradingPostManager(String email, String password) {
		this.email=email;
		this.password=password;
		cookieStore=new BasicCookieStore();
		httpContext=new BasicHttpContext();
		httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
	}
	
	/** Login to server. You do not get if login success, you will have an error code when you will query for JSON
	 */
	public void connect() {
		try {
			HttpClient client = getHttpxClient(LOGIN_URL);
			client.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);
			client.getParams().setParameter(ClientPNames.COOKIE_POLICY,CookiePolicy.BROWSER_COMPATIBILITY);
			//connect
			HttpPost post = new HttpPost("https://account.guildwars2.com/login?redirect_uri=http%3A%2F%2Ftradingpost-live.ncplatform.net%2Fauthenticate%3Fsource%3D%252F&game_code=gw2");
			setRequestHeader(post);
	        post.addHeader("Content-Type", "application/x-www-form-urlencoded");
	        //used for Google analytics post.addHeader("Cookie", "__utma=159804514.329002168.1346334558.1347690665.1348333111.5; __utmz=159804514.1347690665.4.4.utmcsr=t.co|utmccn=(referral)|utmcmd=referral|utmcct=/nRRWuuxk"); //?
	        post.addHeader("DNT", "1");
	        post.addHeader("Host", "account.guildwars2.com");
	        post.addHeader("Origin", "https://account.guildwars2.com");
	        post.addHeader("Referer","https://account.guildwars2.com/login?redirect_uri=http%3A%2F%2Ftradingpost-live.ncplatform.net%2Fauthenticate%3Fsource%3D%252F&game_code=gw2");
			List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
			urlParameters.add(new BasicNameValuePair("email", email));
			urlParameters.add(new BasicNameValuePair("password", password));
			post.setEntity(new UrlEncodedFormEntity(urlParameters));
			response = client.execute(post, httpContext);
			Logger.getLogger(TradingPostManager.class).info("Auth return code: "+response.getStatusLine().getStatusCode());
			
			//catche session ID here
			//Set-Cookie: s=<session-id>; Domain=ncplatform.net; Path=/; Version=1
			for(Cookie c : cookieStore.getCookies())
				if(c.getName().equals("s"))
					sid=c.getValue();
			handleResponse(response,LOGIN_URL);
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	private HttpClient getHttpxClient(String url) {
		if(url.startsWith("http://")) return new DefaultHttpClient();
		else if(url.startsWith("https://"))
			try {
				SchemeRegistry registry = new SchemeRegistry();
		        SSLSocketFactory socketFactory = new SSLSocketFactory(new TrustStrategy() {
		            public boolean isTrusted(final X509Certificate[] chain, String authType) throws CertificateException {
		                return true;
		            }
		        }, org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
		        registry.register(new Scheme("https", 443, socketFactory));
		        ThreadSafeClientConnManager mgr = new ThreadSafeClientConnManager(registry);
		        return new DefaultHttpClient(mgr, new DefaultHttpClient().getParams());
			}  catch(Exception e) {
				e.printStackTrace();
			}
		return null;
	}
	/** Decode response content to return a String
	 * @param is 
	 * @return
	 * @throws IOException
	 */
	public static String decodeResponseBody(InputStream is) throws IOException {
		BufferedReader rd = new BufferedReader(new InputStreamReader(is));
		StringBuffer result = new StringBuffer();
		String line = "";
		while ((line = rd.readLine()) != null)
			result.append(line+"\n");
		//System.out.println(result.toString());
		return line;
	}
	public String getPage(String url) {
		//System.out.println("SID: "+sid);
		HttpClient client = getHttpxClient(url);
		client.getParams().setParameter(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);
		client.getParams().setParameter(ClientPNames.COOKIE_POLICY,CookiePolicy.BROWSER_COMPATIBILITY);
		HttpGet request = new HttpGet(url);
		setRequestHeader(request);
		try {
			response = client.execute(request, httpContext);
			Logger.getLogger(TradingPostManager.class).info("Page return code: "+response.getStatusLine().getStatusCode());
			if(response.getStatusLine().getStatusCode()==401) {
				Logger.getLogger(TradingPostManager.class).error("Error 401: Invalid auhorization");
				return ""; //Invalid authorization
			}
			return handleResponse(response,url);
			/*getRedirectUrl(response.getAllHeaders());
			return decodeResponseBody(response.getEntity().getContent());*/
		} catch(Exception e) {
			e.printStackTrace();
		}
		return "";
	}
	/** Get the session ID
	 * @return Session ID
	 */
	public String getSessionID() {return sid;}
	/** Find the "Location" field in HTTP header and return its URL
	 * @param hs Header list
	 * @return URL
	 */
	public String getRedirectUrl(Header[] hs, String baseUrl) {
		for(int i=0; i<hs.length; i++) {
			//System.out.println(hs[i].getName()+": "+hs[i].getValue());
			if(hs[i].getName().equals("Location"))
				if(hs[i].getValue().startsWith("http://") || hs[i].getValue().startsWith("https://"))
					return hs[i].getValue();
				else {
					try {
						URL url=new URL(baseUrl);
						//System.out.println(url.getProtocol()+"://"+url.getHost()+hs[i].getValue());
						return url.getProtocol()+"://"+url.getHost()+hs[i].getValue();
					} catch(Exception e) {
						e.printStackTrace();
						Logger.getLogger(TradingPostManager.class).error("Url error: "+baseUrl);
					}
					//System.out.println(hs[i].getValue());
				}
		}
		return "";
	}
	/** Set the same header for each request
	 * @param ahm HttpGet or HttpPost
	 */
	private void setRequestHeader(AbstractHttpMessage ahm) {
		ahm.addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
		ahm.addHeader("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
		ahm.addHeader("Accept-Encoding", "deflate");
		ahm.addHeader("Accept-Language", "en-US,en;q=0.8");
		ahm.addHeader("Cache-Control", "max-age=0");
		ahm.addHeader("Connection","keep-alive");
		ahm.setHeader("User-Agent", USER_AGENT);
	}
	/** Process response: if there is a redirection, it will follow the URL and return its content
	 * @param response HttpResponse object (we read its headers)
	 * @param baseUrl URL that call the page, it is used for redirection if we do not have a full url (ie: /account)
	 */
	private String handleResponse(HttpResponse response, String baseUrl) {
		String rUrl=getRedirectUrl(response.getAllHeaders(), baseUrl);
		lastErrorCode=response.getStatusLine().getStatusCode();
		if(!rUrl.isEmpty()) {
			Logger.getLogger(TradingPostManager.class).info("Redirect to: "+rUrl);
			return getPage(rUrl);
		} else
			try {
				return decodeResponseBody(response.getEntity().getContent());
			} catch (Exception e) {
				e.printStackTrace();
				Logger.getLogger(TradingPostManager.class).error("Error while getting document body");
			}
		return "";
	}
	public int getLastErrorCode() {return lastErrorCode;}
}
